﻿#include "dockwindow.h"
#include "ui_dockwindow.h"
#include <QGraphicsDropShadowEffect>
#include <QTimer>
#include <QPaintEvent>
#include <QPainter>
#include <QDebug>

DockWindow::DockWindow(QWidget *parent) :
    QWidget(parent),
    ui(new Ui::DockWindow)
{
    ui->setupUi(this);

    led_on=QIcon(":/new/prefix1/png/light0_b.png");
    led_off=QIcon(":/new/prefix1/png/light0_g.png");
    kDockWidth=10;
//    setWindowFlags(/*Qt::CoverWindow | Qt::Window |*//* Qt::FramelessWindowHint |*/ Qt::SubWindow);
//    setAutoFillBackground(true);
//    setAttribute(Qt::WA_TranslucentBackground);

#if 1 ///此处使用阴影边框，会影响窗口stylesheet的动态设置
    //设置阴影边框
    QGraphicsDropShadowEffect* shadow_effect = new QGraphicsDropShadowEffect();
    shadow_effect->setOffset(0, 0);
    //阴影颜色
    shadow_effect->setColor(QColor(255, 255, 0));
    //阴影半径
    shadow_effect->setBlurRadius(26);
    setGraphicsEffect(shadow_effect);
#endif

    expand_geo_ = new QPropertyAnimation(this, "geometry");
    shrink_geo_ = new QPropertyAnimation(this, "geometry");
    expand_geo_->setDuration(200);
    shrink_geo_->setDuration(200);
    connect(expand_geo_, &QPropertyAnimation::valueChanged, this,
            [this](const QVariant& v) {
        auto size = v.toRect();
        if(size.height() >= kDockWidth + 5 || size.width() >= kDockWidth + 5) {
            this->show();
            if(!is_fixed_)
                ui->title_frame->show();
        }
    });
    connect(shrink_geo_, &QPropertyAnimation::valueChanged, this,
            [this](const QVariant& v) {
        auto size = v.toRect();
        if(size.height() < kDockWidth + 5 || size.width() < kDockWidth + 5) {
            this->hide();
            if(!is_fixed_)
                ui->title_frame->hide();
        }
    });
    connect(expand_geo_, &QPropertyAnimation::finished, this, [this]{is_shrinked_ = false;this->show();});
    connect(shrink_geo_, &QPropertyAnimation::finished, this, [this]{is_shrinked_ = true;this->hide();});
}

DockWindow::~DockWindow()
{
    delete ui;
}

void DockWindow::SetStickArea(StickArea sa, const QPoint &pos)
{
    stick_area_ = sa;
    is_fixed_ = stick_area_ != StickArea::kLRSide;
    resize(size_);
    if(is_fixed_) {
        ui->title_frame->hide();
        int x = (parentWidget()->width() - size_.width())/2;
        int y = 0;
        if(StickArea::kBottom == stick_area_) {
            y = parentWidget()->height() - size_.height();
        }
        SetPosition(QPoint(x, y));
    }
    else
    {
        SetPosition(pos);
    }
    Shrink();
}

void DockWindow::SetPosition(const QPoint &pos)
{
    move(pos);
}

void DockWindow::Update()
{
    if(StickArea::kBottom == stick_area_) {
        int x = (parentWidget()->width() - size_.width())/2;
        int y = parentWidget()->height() - size_.height();
        if(is_shrinked_)
            y = parentWidget()->height() - kDockWidth;
        SetPosition(QPoint(x, y));
    }
}

void DockWindow::SetSize(const QSize &size)
{
    size_ = size;
    update();
}

void DockWindow::SetExpand()
{
    Expand();
}

void DockWindow::Paint(QPaintEvent* e)
{
    QPainter p(this);
    p.setRenderHints(QPainter::Antialiasing); // 设置渲染 图形保真

    auto pat = palette();
    auto color = pat.color(QPalette::Window);

    if (is_shrinked_) {
        color = color.darker();
        color.setAlpha(opacity_);
    }
    QPainterPath path;
    path.addRoundedRect(rect(), 5, 5);
    p.fillPath(path, color);
}

void DockWindow::Expand()
{
    if(!MouseInTitle()) {
        auto start = QRect(geometry().topLeft(), QSize(size_.width(), kDockWidth));
        auto end = start;

        switch (stick_area_) {
        case StickArea::kTop:
            end = start.adjusted(0, 0, 0, size_.height());
            break;
        case StickArea::kBottom:
        {
            end = start.adjusted(0, -size_.height() + kDockWidth, 0, 0);
            break;
        }
        case StickArea::kLRSide:
        {
            start.setSize(QSize(kDockWidth, size_.height()));

            if(AtLeft()) {
                end = start.adjusted(0, 0, size_.width() - kDockWidth, 0);
            } else {
                end = start.adjusted(-size_.width() + kDockWidth, 0, 0, 0);
            }
            break;
        }
        }

        expand_geo_->setStartValue(start);
        expand_geo_->setEndValue(end);
        expand_geo_->start();
    }
}

void DockWindow::Shrink()
{
    if(!MouseInTitle())
    {
        qDebug() << QString("Shrink size_:%1,%2").arg(size_.width()).arg(size_.height());
        auto start = QRect(geometry().topLeft(), size_);
        auto end = start;
        qDebug() << QString("Shrink start width&height:%1,%2").arg(start.size().width()).arg(start.size().height());
        qDebug() << QString("Shrink start x&y&width&height:%1,%2,%3,%4").arg(start.x()).arg(start.y()).arg(start.width()).arg(start.height());

        switch (stick_area_) {
        case StickArea::kTop:
            end = start.adjusted(0, 0, 0, -size_.height() + kDockWidth);
            break;
        case StickArea::kBottom:
        {
            end = start.adjusted(0, size_.height() - kDockWidth, 0, 0);
            break;
        }
        case StickArea::kLRSide:
        {
            if(AtLeft())
                end = start.adjusted(0, 0, -size_.width() + kDockWidth, 0);
            else
                end = start.adjusted(size_.width() - kDockWidth, 0, 0, 0);
            break;
        }
        }

        qDebug() << QString("Shrink end width&height:%1,%2").arg(end.size().width()).arg(end.size().height());
        qDebug() << QString("Shrink end x&y&width&height:%1,%2,%3,%4").arg(end.x()).arg(end.y()).arg(end.width()).arg(end.height());

        shrink_geo_->setStartValue(start);
        shrink_geo_->setEndValue(end);
        shrink_geo_->start();
    }
}

bool DockWindow::MouseInTitle()
{
    auto title_area = ui->title_frame->rect();
    auto pos = cursor().pos();
    pos = mapFromGlobal(pos);
    return title_area.contains(pos);
}

bool DockWindow::AtLeft()
{
    return pos().x() <= 5;
}

bool DockWindow::AtRight()
{
    return geometry().right() + 5 >= parentWidget()->width();
}

bool DockWindow::event(QEvent *event)
{
    switch (event->type()) {
    case QEvent::Enter:
    {
        ///延时300ms考虑到鼠标滑动的速度过快而出现的闪烁问题
        QTimer::singleShot(300,
                           [this]{
            //bool in = this->rect().contains(mapFromGlobal(this->cursor().pos()));
            bool in = true; // 当enter事件触发的时候 鼠标肯定是处于该控件之上了吧
            if(in && is_shrinked_)
                Expand();
        }
        );
        break;
    }
    case QEvent::Leave:
    {
        QTimer::singleShot(300,
                           [this]{
            if(!is_shrinked_) {
                if(StickArea::kLRSide == stick_area_) {
                    if(AtLeft() || AtRight())
                        Shrink();
                }
                else {
                    Shrink();
                }
            }
        }
        );

        break;
    }
    case QEvent::Paint:
    {
        auto e =static_cast<QPaintEvent*>(event);;
        Paint(e);
        break;
    }
    case QEvent::MouseButtonPress:
    {
        auto e =static_cast<QMouseEvent*>(event);
        if(MouseInTitle()) {
            mouse_press_titlebar_ = true;
            y_diff_ = e->pos().y();
            x_diff_ = e->pos().x();
            qDebug() << QString("MouseButtonPress x:%1,y:%2").arg(x_diff_).arg(y_diff_);
        }
        break;
    }
    case QEvent::MouseMove:
    {
        ///是否已经按下鼠标
        if(mouse_press_titlebar_) {
            auto e =static_cast<QMouseEvent*>(event);

            if(is_shrinked_) {
                int diffy = e->pos().y() - y_diff_;
                int posy = pos().y() + diffy;
                if(posy < parentWidget()->height()-5 && posy > 0)
                    move(pos().x(), posy);
            } else {
                qDebug() << QString("MouseMove x:%1,y:%2").arg(e->pos().x()).arg(e->pos().y());
                int diffx = e->pos().x() - x_diff_;
                int diffy = e->pos().y() - y_diff_;
                qDebug() << QString("MouseMove diffx:%1,diffy:%2").arg(diffx).arg(diffy);
                int posx = pos().x() + diffx;
                int posy = pos().y() + diffy;
                qDebug() << QString("MouseMove pos_x:%1,pos_y:%2").arg(pos().x()).arg(pos().y());
                qDebug() << QString("MouseMove pos_x_cal:%1,pos_y_cal:%2").arg(posx).arg(posy);
                qDebug() << QString("MouseMove geometry().right():%1, parentWidget()->width():%2").arg(geometry().right()).arg(parentWidget()->width());
                if(parentWidget()->rect().contains(QPoint(posx, posy)))
                    move(posx, posy);
            }
        }
        break;
    }
    case QEvent::MouseButtonRelease:
    {
        mouse_press_titlebar_ = false;

        // 释放鼠标按键时判断
        if(AtLeft()) {
            move(0, y());
        } else if(AtRight()) {
            move(parentWidget()->width() - size_.width(), pos().y());
        }
        break;
    }
    default:
        break;
    }

    return QWidget::event(event);
}
